#include "Pcm2AacThread.h"
#include <QDebug>
extern "C"
{
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
#include <libavutil/avutil.h>
#include <libswresample/swresample.h>
}

Pcm2AacThread::Pcm2AacThread()
{

}

void Pcm2AacThread::run()
{
	qDebug() << "开始转换";

	//1 打开音频编码器
	const AVCodec* codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
	if (!codec)
	{
		qDebug() << "avcodec_find_encoder error";
		return;
	}
	AVCodecContext* c = avcodec_alloc_context3(codec);
	if (!c)
	{
		qDebug() << "avcodec_alloc_context3 error";
		return;
	}
	c->bit_rate = 64000;
	c->sample_rate = 44100;
	c->sample_fmt = AV_SAMPLE_FMT_FLTP;
	c->channel_layout = AV_CH_LAYOUT_STEREO;
	c->channels = 2;
	c->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;

	int ret = avcodec_open2(c, codec, NULL);
	if (ret < 0)
	{
		qDebug() << "avcodec_open2 error";
		return;
	}
	qDebug() << "avcodec_open2 success!";

	//2 打开输出封装的上下文
	AVFormatContext* oc = NULL;
	avformat_alloc_output_context2(&oc, NULL, NULL, outFile.toStdString().c_str());
	if (!oc)
	{
		qDebug() << "avformat_alloc_output_context2 error";
		return;
	}

	AVStream* st = avformat_new_stream(oc, NULL);
	st->codecpar->codec_tag = 0;
	avcodec_parameters_from_context(st->codecpar, c);

	//3  open io ,write head
	ret = avio_open(&oc->pb, outFile.toStdString().c_str(), AVIO_FLAG_WRITE);
	if (ret < 0)
	{
		qDebug() << "avio_open error";
		return;
	}
	ret = avformat_write_header(oc, NULL);

	//44100 16 2
	//4 创建音频重采样上下文
	SwrContext* actx = NULL;
	actx = swr_alloc_set_opts(actx,
		c->channel_layout, c->sample_fmt, c->sample_rate,	//输出格式
		AV_CH_LAYOUT_STEREO, AV_SAMPLE_FMT_S16, 44100,		//输入格式
		0, 0);
	if (!actx)
	{
		qDebug() << "swr_alloc_set_opts error";
		return;
	}
	ret = swr_init(actx);
	if (ret < 0)
	{
		qDebug() << "swr_init error";
		return;
	}


	//5 打开输入音频文件，进行重采样
	AVFrame* frame = av_frame_alloc();
	frame->format = AV_SAMPLE_FMT_FLTP;
	frame->channels = 2;
	frame->channel_layout = AV_CH_LAYOUT_STEREO;
	frame->nb_samples = 1024;//一帧音频存放的样本数量
	ret = av_frame_get_buffer(frame, 0);
	if (ret < 0)
	{
		qDebug() << "av_frame_get_buffer error";
		return;
	}

	int readSize = frame->nb_samples * 2 * 2;
	char* pcm = new char[readSize];

	FILE* fp = fopen(inFile.toStdString().c_str(), "rb");

	for (;;)
	{
		int len = fread(pcm, 1, readSize, fp);
		if (len <= 0)break;
		const uint8_t* data[1];
		data[0] = (uint8_t*)pcm;

		len = swr_convert(actx, frame->data, frame->nb_samples,
			data, frame->nb_samples
		);
		if (len <= 0)
			break;


		AVPacket pkt;
		av_init_packet(&pkt);

		//6 音频编码
		ret = avcodec_send_frame(c, frame);
		if (ret != 0) continue;
		ret = avcodec_receive_packet(c, &pkt);
		if (ret != 0) continue;


		//7 音频封装如aac文件
		pkt.stream_index = 0;
		pkt.pts = 0;
		pkt.dts = 0;
		ret = av_interleaved_write_frame(oc, &pkt);


		qDebug() << "*[" << len << "]";


	}
	delete pcm;
	pcm = NULL;

	//写入视频索引
	av_write_trailer(oc);

	//关闭视频输出io
	avio_close(oc->pb);

	//清理封装输出上下文
	avformat_free_context(oc);

	//关闭编码器
	avcodec_close(c);

	//清理编码器上下文
	avcodec_free_context(&c);
	qDebug() << "转换 结束";
}
void Pcm2AacThread::Start() {
	qDebug() << "开始线程";
	this->start();
}

Pcm2AacThread::~Pcm2AacThread()
{
}
